/* Copyright (C) 2014-2016 Dan Chapman <dpniel@ubuntu.com>

   This file is part of the dekko

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of
   the License or (at your option) version 3 or any later version
   accepted by the membership of KDE e.V. (or its successor approved
   by the membership of KDE e.V.), which shall act as a proxy
   defined in Section 14 of version 3 of the license.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef RECIPIENTS_H
#define RECIPIENTS_H

#include <QObject>
#include <QPointer>
#include <QSharedPointer>
#include <QSortFilterProxyModel>
#include "Composer/Recipients.h"
#include "Imap/Parser/MailAddress.h"
#include "app/Components/QmlObjectListModel.h"
#include "app/Contacts/ContactsModel.h"
#include "app/Accounts/MultipleAccountSenderIdentityModel.h"

namespace Dekko
{
namespace Contacts
{
class Contact;
class ContactsModel;
}
class Recipient : public QObject
{
    Q_OBJECT
    Q_PROPERTY(Type type READ type WRITE setType NOTIFY typeChanged)
    Q_PROPERTY(QString address READ address WRITE setAddress NOTIFY recipientChanged)
//    Q_PROPERTY(QString displayName READ displayName NOTIFY recipientChanged)
    Q_PROPERTY(QString initials READ initials NOTIFY recipientChanged)
    Q_PROPERTY(QString name READ name NOTIFY recipientChanged)
    Q_PROPERTY(QString email READ email NOTIFY recipientChanged)
    Q_PROPERTY(QVariantMap contactInfo READ contactInfo NOTIFY recipientChanged)
    Q_PROPERTY(bool isInContacts READ isInContacts NOTIFY recipientChanged)
    Q_ENUMS(Type)
public:
    explicit Recipient(QObject *parent = 0);

    enum Type { TO, CC, BCC, FROM, SENDER, REPLY_TO };

    Type type() const;
    void setType(const Type type);
    QString address() const;
    void setAddress(const QString &address);
    QString initials();
    QString name();
    QString email() const;
    QVariantMap contactInfo();
    bool isInContacts();

    Imap::Message::MailAddress mailAddress() const;
    Q_INVOKABLE void setContactsModel(Contacts::ContactsModel * model);

public slots:
    void addToContacts();
    void removeFromContacts();

signals:
    void typeChanged();
    void recipientChanged();

private:
    Type m_type;
    QString m_address;
    Imap::Message::MailAddress m_mailAddress;
    QString m_contactId;
    QPointer<Contacts::ContactsModel> m_contacts;
};

class Recipients : public QObject
{
    Q_OBJECT
    // Model has an api similar to QLIst and can be used in qml
    Q_PROPERTY(QObject *model READ model NOTIFY modelsChanged)

public:
    explicit Recipients(QObject *parent = 0);
    QObject *model() const { return m_model; }
    bool buildRecipientList(const int mode, const QModelIndex &message);
    Composer::RecipientList toRecipientList() const;

    void setContacts(QObject *contacts);
    void setIdentityModel(Accounts::MultipleAccountSenderIdentityModel *identities);

    bool hasValidToDestination();

signals:
    void modelsChanged();

public slots:
    // We only implement an addRecipients method so we don't have to create Recipient
    // instances in qml and have to reparent them and get that weird ownership situation.
    // All other operations can be done on the model directly using it's qlist api.
    // BUt by all means if it makes sense to append a recipient directly on the model then go for it.
    void addRecipient(const int &type, const QString &address);
    void clear();
    // These are the addresses to include with every every message.
    void setIncludes(const QStringList &includes, const bool isCc);
    void clearIncludes(const bool isCc);


private:
    Composer::RecipientList getRecipientsFromMessage(const QModelIndex &message);
    Composer::RecipientList deduplicatedAndJustToCcBcc(Composer::RecipientList input);
    Composer::RecipientList mapRecipients(Composer::RecipientList input, const QMap<Composer::RecipientKind, Composer::RecipientKind>& mapping);
    bool buildRecipientList(const int mode, const Composer::RecipientList &originalRecipients,
                                            const QList<QUrl> &headerListPost, const bool headerListPostNo);
    bool prepareReplyAll(const Composer::RecipientList &recipients, Composer::RecipientList &output);
    bool prepareReply(const Composer::RecipientList &recipients, const QList<QUrl> headerListPost, Composer::RecipientList &output);
    bool prepareReplyList(const QList<QUrl> &headerListPost, const bool headerListPostNo, Composer::RecipientList &output);
    bool appendRecipientsFromList(const Composer::RecipientList &recipients);

    QStringList m_ccIncludes;
    QStringList m_bccIncludes;
    QQmlObjectListModel<Recipient> *m_model;
    QPointer<Contacts::ContactsModel> m_contacts;
    QPointer<Accounts::MultipleAccountSenderIdentityModel> m_identModel;
};

class RecipientsFilterModel : public QSortFilterProxyModel
{
    Q_OBJECT
    Q_PROPERTY(QAbstractItemModel *source READ sourceModel WRITE setSource NOTIFY sourceChanged)
    Q_ENUMS(FilterRole)
public:
    explicit RecipientsFilterModel(QObject *parent=0);
    enum FilterRole {
        FILTER_TO,
        FILTER_CC,
        FILTER_BCC
    };

    void setSource(QAbstractItemModel *source);
    // Get's the index of the recipient in the source model
    // obj should be model.qtObject.
    Q_INVOKABLE int getDeproxifiedIndex(QVariant obj);

signals:
    void sourceChanged();

protected:
    bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const;

private:
    QPointer<QQmlObjectListModel<Recipient> > m_model;
};
}
#endif // RECIPIENTS_H
